﻿using System.Collections.Generic;
using System.Linq;

namespace dPet.Application.Services.Implementation
{
	using AutoMapper;
	using dPet.Application.DataObjects;
	using dPet.Application.QueryObjects;
	using dPet.Domain.Models;
	using dPet.Domain.Repositories;
	using dPet.Domain.Services;
	using dPet.Domain.Specifications;
	using dPet.Infrastructure.Logging;
	using Hangerd;
	using Hangerd.Extensions;
	using Hangerd.Repository;

	public class SalesService : ServiceBase, ISalesService
	{
		#region Repository

		private readonly IHospitalRepository _hospitalRepository;
		private readonly IProductRepository _productRepository;
		private readonly ISaleOrderRepository _saleOrderRepository;
		private readonly IInventoryReducingRecordRepository _inventoryReducingRecordRepository;

		#endregion

		#region Services

		private readonly IInvoicingDomainService _invoicingDomainService;

		#endregion

		#region Constructors

		public SalesService(
			IRepositoryContext unitOfWork,
			IHospitalRepository hospitalRepository,
			IProductRepository productRepository,
			ISaleOrderRepository saleOrderRepository,
			IInventoryReducingRecordRepository inventoryReducingRecordRepository,
			IInvoicingDomainService invoicingDomainService)
			: base(unitOfWork)
		{
			_hospitalRepository = hospitalRepository;
			_productRepository = productRepository;
			_saleOrderRepository = saleOrderRepository;
			_inventoryReducingRecordRepository = inventoryReducingRecordRepository;
			_invoicingDomainService = invoicingDomainService;
		}

		#endregion

		#region SaleOrder

		public MessagedResult<SaleOrderDto> CreateSaleOrder(string hospitalId, MembershipLevelDto membershipLevelDto, ShoppingCartItemDto[] items, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "销售订单管理", "创建订单", (ref SaleOrder order) =>
			{
				if (items == null || items.Length == 0)
				{
					throw new HangerdException("购买列表为空");
				}

				var hospital = _hospitalRepository.Get(hospitalId, false);

				if (hospital == null)
				{
					throw new HangerdException("医院信息不存在");
				}

				var productsFound = new Dictionary<string, Product>(items.Length);
				var shoppingCart = new List<ShoppingCartItem<Product>>();

				foreach (var item in items)
				{
					if (!productsFound.ContainsKey(item.ItemId))
					{
						var product = _productRepository.Get(item.ItemId, true, p => p.Inventories);

						if (product == null)
						{
							throw new HangerdException("商品信息读取异常:{0}", item.ItemId);
						}

						productsFound.Add(item.ItemId, product);
					}

					shoppingCart.Add(new ShoppingCartItem<Product>(productsFound[item.ItemId], item.Quantity));
				}

				order = _invoicingDomainService.CreateSaleOrder(hospital, (MembershipLevel)membershipLevelDto, shoppingCart, @operator.LoginName);

				_saleOrderRepository.Add(order, true);
				
				UnitOfWork.Commit();

				return Mapper.Map<SaleOrder, SaleOrderDto>(order);
			}, successMessage: "下单成功");
		}

		public IEnumerable<SaleOrderDto> GetSaleOrders(string hospitalId, SaleOrderQueryDto queryDto, int pageIndex, int pageSize, out int totalNumber)
		{
			var spec = SaleOrderSpecifications.HospitalIdEquals(hospitalId);

			if (queryDto.Status.HasValue)
			{
				spec &= SaleOrderSpecifications.StatusEquals((OrderStatus)queryDto.Status.Value);
			}

			if (!string.IsNullOrWhiteSpace(queryDto.OrderNumber))
			{
				spec &= SaleOrderSpecifications.OrderNumberEquals(queryDto.OrderNumber);
			}

			var orders = _saleOrderRepository.GetAll(spec, false)
				.OrderByDescending(c => c.CreateTime)
				.Paging(pageIndex, pageSize, out totalNumber);

			return Mapper.Map<IEnumerable<SaleOrder>, IEnumerable<SaleOrderDto>>(orders);
		}

		public SaleOrderDto GetSaleOrder(string orderId)
		{
			var order = _saleOrderRepository.Get(orderId, false, so => so.OrderLines);

			return Mapper.Map<SaleOrder, SaleOrderDto>(order);
		}

		public SaleOrderDto GetSaleOrder(string orderId, OrderStatusDto statusDto)
		{
			var spec = SaleOrderSpecifications.IdEquals(orderId)
				& SaleOrderSpecifications.StatusEquals((OrderStatus)statusDto);

			var order = _saleOrderRepository.Get(spec, false, so => so.OrderLines);

			return Mapper.Map<SaleOrder, SaleOrderDto>(order);
		}

		public MessagedResult<bool> PaySaleOrder(string orderId, PaymentMethodDto paymentMethodDto, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "销售订单管理", "支付订单", (ref SaleOrder order) =>
			{
				order = _saleOrderRepository.Get(orderId, true);

				if (order == null)
				{
					throw new HangerdException("订单信息不存在");
				}

				order.Complete((PaymentMethod)paymentMethodDto, @operator.LoginName);

				_saleOrderRepository.Update(order, true);
				
				UnitOfWork.Commit();

				return true;
			});
		}

		public MessagedResult<bool> CancelSaleOrder(string orderId, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "销售订单管理", "取消订单", (ref SaleOrder order) =>
			{
				order = _saleOrderRepository.Get(orderId, true);

				if (order == null)
				{
					throw new HangerdException("订单信息不存在");
				}

				//取消订单
				order.Cancel(@operator.LoginName);

				//删除出库记录
				_inventoryReducingRecordRepository.RemoveRecordsByOrder(order);

				_saleOrderRepository.Update(order, true);
				
				UnitOfWork.Commit();

				return true;
			});
		}

		#endregion
	}
}
